<?php
/**
 * Created by PhpStorm.
 * User: cailusen
 * Date: 2019-02-27
 * Time: 11:55
 */

namespace Biz\service;

use Biz\cache\ShopClassifies as cShopClassifies;
use Biz\model\CategoryStatusMap as mCategoryStatusMap;
use Biz\model\ShopCategoryClassify as mShopCategoryClassify;
use Biz\model\wiki\WikiRankingCategory as mWikiRankingCategory;
use Biz\service\esSearch\Goods as esGoods;
use Biz\validate\ShopClassifies as vShopClassifies;
use Doraemon\model\Category as mCategory;
use Doraemon\tools\ImgUrl;

class ShopClassify
{

    private static function admGetClassifyListByPIds($parentIds = [0], $status = [
        mShopCategoryClassify::STATUS_NORMAL,
        mShopCategoryClassify::STATUS_HIDE
    ])
    {
        $parentIds = array_filter($parentIds);
        if (!$parentIds) {
            $allClassifies = mShopCategoryClassify::getClassifyByPids([0]);
            $parentIds = $allClassifies ? array_column($allClassifies[0], 'id') : [];
        }
        $classifyList = $parentIds ? mShopCategoryClassify::getListByIds($parentIds, $status) : [];
        $chirldClassifies = $parentIds ? mShopCategoryClassify::getClassifyByPids($parentIds, $status) : [];

        $Rst = [];
        if ($classifyList && is_array($classifyList)) foreach ($classifyList as $parentId => $item) {
            $Rst[$parentId] = $item;
            if ($item['deep'] == mShopCategoryClassify::DEEP_FIRST_CLASSIFY) {
                $Rst[$parentId]['classifies'] = isset($chirldClassifies[$parentId]) ? self::admGetClassifyListByPIds(array_column($chirldClassifies[$parentId], 'id')) : [];
            } else if ($item['deep'] == mShopCategoryClassify::DEEP_SECOND_CLASSIFY) {
                $cateIds = $parentIds = [];
                if (isset($chirldClassifies[$parentId])) foreach ($chirldClassifies[$parentId] as $chirldClassify) {
                    if ($chirldClassify['cate_id']) {
                        $cateIds[] = $chirldClassify['cate_id'];
                    } else {
                        $parentIds[] = $chirldClassify['id'];
                    }
                }
                $Rst[$parentId] = array_merge($Rst[$parentId], [
                    'cate_list' => mCategory::selectCategorys($cateIds),
                    'classifies' => $parentIds ? self::admGetClassifyListByPIds($parentIds) : []
                ]);
            } else if ($item['deep'] == mShopCategoryClassify::DEEP_THIRD_CLAORCATE) {
                $Rst[$parentId] = array_merge($Rst[$parentId], [
                    'cate_list' => mCategory::selectCategorys(isset($chirldClassifies[$parentId]) ? array_column($chirldClassifies[$parentId], 'cate_id') : [])
                ]);
            }

        }

        return $Rst;
    }

    public static function quiltGetClassifyByIds($classifyIds)
    {
        list($cacheData, $noCacheKeys) = cShopClassifies::mGetItems($classifyIds);
        if ($noCacheKeys) {
            $infos = self::admGetClassifyListByPIds($noCacheKeys, [mShopCategoryClassify::STATUS_NORMAL]);
            cShopClassifies::mSetItems($infos);
            return $cacheData + $infos;
        } else {
            return $cacheData;
        }
    }

    public static function quiltGetClassifyById($classifyId)
    {
        $item = cShopClassifies::getItem($classifyId);
        if (!$item) {
            $infos = self::admGetClassifyListByPIds([$classifyId], [mShopCategoryClassify::STATUS_NORMAL]);
            $item = $infos[$classifyId] ?? [];
            cShopClassifies::mSetItems($infos);
        }
        return $item;
    }

    public static function goodsListByFilter($classifyId, $sortType, array $params, $page, $areaCode)
    {
        if ($classifyId && $classifyInfo = self::quiltGetClassifyById($classifyId)) {
            if (in_array($classifyInfo['deep'], [
                mShopCategoryClassify::DEEP_FIRST_CLASSIFY,
                mShopCategoryClassify::DEEP_SECOND_CLASSIFY
            ])) {
                $params = self::verifyParams($params);
                if (isset($params['category'])) { //存在三级分类
                    $cateIds = [];
                    foreach ($params['category'] as $classifyId) {
                        $classifyInfo = self::quiltGetClassifyById($classifyId);
                        //三级分类
                        if ($classifyInfo['deep'] == mShopCategoryClassify::DEEP_THIRD_CLAORCATE) {
                            $cateIds = array_merge($cateIds, array_column($classifyInfo['cate_list'], 'id'));
                        } else {
                            throw new \Exception('无效的三级分类');
                        }
                    }
                } else {
                    if ($classifyInfo['deep'] == mShopCategoryClassify::DEEP_FIRST_CLASSIFY) {
                        $cateIds = [];
                        foreach ($classifyInfo['classifies'] as $secClassify) {
                            $cateIds = array_merge($cateIds, array_column($secClassify['cate_list'], 'id'));
                            foreach ($secClassify['classifies'] as $thirdClassify) {
                                $cateIds = array_merge($cateIds, array_column($thirdClassify['cate_list'], 'id'));
                            }
                        }
                    } else if ($classifyInfo['deep'] == mShopCategoryClassify::DEEP_SECOND_CLASSIFY) {
                        $cateIds = array_column($classifyInfo['cate_list'], 'id');
                        $thirdClassifies = [];
                        foreach ($classifyInfo['classifies'] as $classify) {
                            $cateIds = array_merge($cateIds, array_column($classify['cate_list'], 'id'));
                            $thirdClassifies[] = [
                                "id" => $classify['id'],
                                "title" => $classify['classify_name'],
                                "icon" => $classify['icon'] ? ImgUrl::getUrl(ImgUrl::APPTYPE_OP, $classify['icon'], ImgUrl::IMAGE_SIZE_OP_ORI) : '',
                            ];
                        }
                        $thirdClassifies = array_slice($thirdClassifies, 0, 4);
                    }
                }
                $cateIds = array_unique($cateIds);
                $where = array_filter([
                    'category_id' => $cateIds,
                    'second_category_id' => $cateIds,
                    'third_category_id' => $cateIds,
                    'four_category_id' => $cateIds,
                    'min_price_has_stock' => isset($params['price_range'][0]) ? $params['price_range'][0] : 0,
                    'max_price_has_stock' => isset($params['price_range'][1]) ? $params['price_range'][1] : 0,
                    'brand_id' => isset($params['brand']) ? $params['brand'] : [],
                    'source' => esGoods::SOURCE_APP
                ]);
                $results = SearchGoods::searchEntrance($where, esGoods::SCENES_CATEGORY_LIST, $sortType, $page);

                $goodsList = Goods::Goods($results['rows'], Goods::FIELDS_GROUP_LIST, ['area_code' => $areaCode]);
                $rst['is_over'] = $results['is_over'];
                $k = 0;
                foreach ($goodsList as $goodsId => $item) {
                    if ($k == 4 && isset($thirdClassifies) && $thirdClassifies && $page == 1) {
                        $rst['list'][] = [
                            'type' => 2,
                            'type_desc' => '三级分类',
                            'classifies' => $thirdClassifies
                        ];
                    }
                    $rst['list'][] = [
                        'type' => 1,
                        'type_desc' => '商品',
                        'goods_info' => $item
                    ];
                    $k++;
                }
                return $rst;
            } else {
                throw new \Exception('无效的分类ID' . $classifyId);
            }
        } else {
            throw new \Exception('无效的分类ID' . $classifyId);
        }
    }

    public static function verifyParams($params)
    {
        $result = [];
        if ($params) {
            foreach ($params as $param) {
                if ($param['type'] == 'price_range') {
                    $result['price_range'] = array_column($param['list'], 'title');
                    sort($result['price_range']);
                } else if ($param['type'] == 'category') {
                    $result['category'] = array_column($param['list'], 'id');
                } else if ($param['type'] == 'brand') {
                    $result['brand'] = array_column($param['list'], 'id');
                }
            }
        }
        return $result;
    }


    public static function delCache($classifyId)
    {
        cShopClassifies::delItem($classifyId);
        $classifyInfo = mShopCategoryClassify::getInfo($classifyId, [
            mShopCategoryClassify::STATUS_NORMAL,
            mShopCategoryClassify::STATUS_HIDE
        ]);
        if ($classifyInfo['parent_id']) {
            self::delCache($classifyInfo['parent_id']);
        } else {
            cShopClassifies::delItem(0);
        }
        return true;
    }

    public static function admGetClassifyById($classifyId)
    {
        $classifyInfo = mShopCategoryClassify::getInfo($classifyId, [
            mShopCategoryClassify::STATUS_NORMAL,
            mShopCategoryClassify::STATUS_HIDE
        ]);
        if ($classifyInfo['deep'] == mShopCategoryClassify::DEEP_FIRST_CLASSIFY) {
            $secClassifyInfos = self::admClassifiesOrCates($classifyId);
            $classifyInfo['chirld_classifies'] = implode(',', array_column($secClassifyInfos['list'], 'classify_name'));
        } else if ($classifyInfo['deep'] == mShopCategoryClassify::DEEP_SECOND_CLASSIFY) {
            $thirClassifyInfos = self::admClassifiesOrCates($classifyId);
            $thirCategories = self::admClassifiesOrCates($classifyId, 'cate_list');
            $classifyInfo['chirld_classifies'] = implode(',', array_column($thirClassifyInfos['list'], 'classify_name'));
            $classifyInfo['cate_ids'] = array_column($thirCategories['list'], 'id');
        } else if ($classifyInfo['deep'] == mShopCategoryClassify::DEEP_THIRD_CLAORCATE) {
            $fourCategories = self::admClassifiesOrCates($classifyId, 'cate_list');
            $classifyInfo['cate_ids'] = array_column($fourCategories['list'], 'id');
        } else {
            $classifyInfo['cate_ids'] = [];
        }
        return $classifyInfo;
    }

    public static function admClassifiesOrCates($parentId = 0, $field = 'classifies')
    {
        $classifies = self::admGetClassifyListByPIds([$parentId]);
        if ($parentId) {
            $classifies = $classifies[$parentId][$field];
        }
        if ($field == 'classifies') foreach ($classifies as $parentId => $classify) {
            $classifies[$parentId]['icon_url'] = $classify['icon'] ? ImgUrl::getUrl(ImgUrl::APPTYPE_OP, $classify['icon'], ImgUrl::IMAGE_SIZE_OP_ORI) : '';
        }
        return [
            'list' => $classifies,
            'total' => count($classifies)
        ];
    }

    public static function admAddClassifies($data, $cateIds = [], $categoryStatusMap = [])
    {
        switch ($data['deep']) {
            case mShopCategoryClassify::DEEP_FIRST_CLASSIFY:
                if (!vShopClassifies::validate($data, 'addfirstclassify')) {
                    throw new \Exception(vShopClassifies::firstError());
                }
                break;
            case  mShopCategoryClassify::DEEP_SECOND_CLASSIFY:
                if (!vShopClassifies::validate($data, 'addsecclassify')) {
                    throw new \Exception(vShopClassifies::firstError());
                }
                break;
            case mShopCategoryClassify::DEEP_THIRD_CLAORCATE:
                if (!vShopClassifies::validate($data, 'addthirdclassify')) {
                    throw new \Exception(vShopClassifies::firstError());
                }
                break;
        }
        $classifyId = mShopCategoryClassify::admAddClassify($data);
        if ($cateIds) {
            foreach ($cateIds as $cateId) {
                if ($cateId) {
                    $classifycateData = [
                        'cate_id' => $cateId,
                        'admin_id' => $data['admin_id'],
                        'parent_id' => $classifyId,
                        'deep' => $data['deep'] + 1,
                        'status' => mShopCategoryClassify::STATUS_NORMAL,
                    ];
                    mShopCategoryClassify::admAddClassify($classifycateData);
                }
            }
        }

        if ($categoryStatusMap) {
            self::updateCategoryStatusMap($classifyId, $categoryStatusMap);
        }

        return $classifyId;
    }

    public static function admSortCalssifies($sortInfo)
    {
        mShopCategoryClassify::admSortClassify($sortInfo);
    }


    public static function admEditClassify($data, $classifyId, $cateIds = [], $categoryStatusMap = [])
    {
        mShopCategoryClassify::updateClassify($data, ['id' => $classifyId]);
        $cateIds = array_filter($cateIds);
        // 如果没有cateIds的话，说明，这可能是个一级分类，或者说是，没有cateIds的二三级分类。 这种情况下，可以将这些分类对应的cate_id置为0
        if (!$cateIds) {
            mShopCategoryClassify::updateClassify(['status' => mShopCategoryClassify::STATUS_DELETE], [
                'parent_id' => $classifyId,
                'cate_id[!]' => 0
            ]);
        }

        // 如果有cateIds的话，说明这有可能是在原来没有cate_id的基础上新增的，也有可能是在之前有的基础上新增的。 也有可能是在之前的基础上修改的。 这个时候，应该根据分类id查询数据。
        // 如果数据里包含 cate_id的话，就保留，否的的话，就删除。 最终取cate_id的差集，把新增的数据入库
        if ($cateIds) {
            $insertCateId = [];
            $normalId = $deleteId = [];
            $categoryInfo = mShopCategoryClassify::select('*', ['parent_id' => $classifyId, 'cate_id[!]' => 0]);
            // 如果之前存在的话
            if ($categoryInfo) {
                foreach ($categoryInfo as $info) {
                    if (in_array($info['cate_id'], $cateIds)) {
                        $normalId[] = $info['id'];
                    } else {
                        $deleteId[] = $info['id'];
                    }
                    $insertCateId[] = $info['cate_id'];
                }

                if ($normalId) {
                    mShopCategoryClassify::updateClassify(['status' => mShopCategoryClassify::STATUS_NORMAL], ['id' => $normalId]);
                }

                if ($deleteId) {
                    mShopCategoryClassify::updateClassify(['status' => mShopCategoryClassify::STATUS_DELETE], ['id' => $deleteId]);
                }
            }

            $cateIds = array_filter(array_diff($cateIds, $insertCateId));

            if ($cateIds) {
                foreach ($cateIds as $cateId) {
                    $classifyCateData[] = [
                        'cate_id' => $cateId,
                        'admin_id' => $data['admin_id'],
                        'parent_id' => $classifyId,
                        'deep' => $data['deep'] + 1,
                        'status' => mShopCategoryClassify::STATUS_NORMAL,
                        'addtime' => date("Y-m-d H:i:s"),
                        'edittime' => date("Y-m-d H:i:s"),
                    ];
                }
                mShopCategoryClassify::insert($classifyCateData);
            }
        }

        if ($categoryStatusMap) {
            self::updateCategoryStatusMap($classifyId, $categoryStatusMap); // 更新类目与状态的映射表
        }

        return $classifyId;
    }

    /**
     * 更新类目与状态的映射表
     * @param $classifyId
     * @param $categoryStatusMap
     * @return bool|\PDOStatement
     */
    private static function updateCategoryStatusMap($classifyId, $categoryStatusMap)
    {
        $list = mCategoryStatusMap::select('*', ['category_id' => $classifyId]);
        foreach (mCategoryStatusMap::TYPE_STATUS as $item) {
            $insertCateId = [];
            $normalId = $deleteId = [];
            if ($item == mCategoryStatusMap::TYPE_STATUS_DECORATION) {
                $data = $categoryStatusMap['decoration_status'] ?: [];
            } else {
                $data = $categoryStatusMap['house_status'] ?: [];
            }

            foreach ($list as $info) {
                if ($info['status_type'] != $item) {
                    continue;
                }

                if (in_array($info['user_status'], $data)) {
                    $normalId[] = $info['id'];
                } else {
                    $deleteId[] = $info['id'];
                }
                $insertCateId[] = $info['user_status'];
            }

            if ($normalId) {
                mCategoryStatusMap::update(['recommend_status' => mCategoryStatusMap::STATUS_NORMAL], ['id' => $normalId]);
            }

            if ($deleteId) {
                mCategoryStatusMap::update(['recommend_status' => mCategoryStatusMap::STATUS_DELETE], ['id' => $deleteId]);
            }

            $data = array_filter(array_diff($data, $insertCateId));

            if ($data) {
                foreach ($data as $status) {
                    $res[] = [
                        'category_id' => $classifyId,
                        'status_type' => $item,
                        'user_status' => $status,
                        'recommend_status' => mCategoryStatusMap::STATUS_NORMAL,
                        'addtime' => date('Y-m-d H:i:s'),
                        'edittime' => date('Y-m-d H:i:s'),
                    ];
                }

                mCategoryStatusMap::insert($res);
            }
        }

        return true;
    }

    public static function admputClassify($data, $classifyId)
    {
        if (isset($data['status'])) {
            $status = $data['status'] == 'off' ? mShopCategoryClassify::STATUS_HIDE : mShopCategoryClassify::STATUS_NORMAL;

            $data = mShopCategoryClassify::select('*', ['parent_id' => $classifyId, 'status' => [1, 2]]);
            if ($data) {
                $category = self::getCategoryIdByParent($data);
                $classifyId = array_merge([$classifyId], array_column($category, 'id'));
            }

            mShopCategoryClassify::updateClassify(['status' => $status], ['id' => $classifyId]);
            mCategoryStatusMap::update(['recommend_status' => $status], ['category_id' => $classifyId]);

        } else {
            mShopCategoryClassify::updateClassify([$data['name'] => $data['value']], ['id' => $classifyId]);
        }
    }

    public static function admdelClassify($classifyId)
    {
        $data = mShopCategoryClassify::select('*', ['parent_id' => $classifyId, 'status' => [1, 2]]);
        if ($data) {
            $category = self::getCategoryIdByParent($data);
            $classifyId = array_merge([$classifyId], array_column($category, 'id'));
        }

        $result = mShopCategoryClassify::updateClassify(['status' => mShopCategoryClassify::STATUS_DELETE], ['id' => $classifyId]);

        if ($result) {
            mCategoryStatusMap::update(['recommend_status' => mCategoryStatusMap::STATUS_DELETE], ['category_id' => $classifyId]);
        }

        return $result;
    }

    /**
     * 根据父级分类获取其所有子分类
     * @param $data
     * @return array
     */
    public static function getCategoryIdByParent($data)
    {
        // 每次查询完之后与上级合并
        $categoryId = array_column($data, 'id');
        $category = mShopCategoryClassify::select('*', ['parent_id' => $categoryId, 'status' => [1, 2]]);

        $list = $data;
        if ($category) {
            $list = array_merge($data, self::getCategoryIdByParent($category));
        }
        return $list;
    }

    public static function mGetClassifyRankingIds(array $classifyIds)
    {
        $redis = new \Hhz\Redis\newCache(\hhz\constant\redis\redisKeys::KEY_B_CACHE_CATEGORY_CLASSIFY_RANKING);
        list($list, $noCacheKeys)  = $redis->getCaches($classifyIds);
        if ($noCacheKeys) {
            $mList = [];
            foreach ($noCacheKeys as $classifyId) {
                $rankingIds = self::getClassifyRankingIds($classifyId);
                $redis->setCache($rankingIds,$classifyId);
                $mList[$classifyId] = $rankingIds;
            }
            $list = $list + $mList;
        }
        return $list;
    }

    public static function getClassifyRankingIds($classifyId)
    {
        $where = [
            'OR' => [
                'parent_id' => $classifyId,
                'id' => $classifyId,
            ],
            'deep' => [1, 2]
        ];
        $relateClassifyList = mShopCategoryClassify::select(['id', 'deep', 'classify_name'], $where);
        $relateClassifyIds = array_column($relateClassifyList, 'id');
        $relateClassifyList = array_column($relateClassifyList, null, 'id');
        if (isset($relateClassifyList[$classifyId])) {
            if ($relateClassifyList[$classifyId]['deep'] == 2) {
                $relateClassifyIds = $classifyId;
            }
            $categoryIds = $relateClassifyIds ? mShopCategoryClassify::select('cate_id', ['cate_id[>]' => 0, 'parent_id' => $relateClassifyIds]) : [];
            $rankingIds = [];
            if ($categoryIds) {
                $categoryIds = array_filter(array_unique($categoryIds));
                $rankingIds = mWikiRankingCategory::selectByWhere(['cate_state[!]' => mWikiRankingCategory::STATUS_DELETE, 'cate_id' => $categoryIds], 'ranking_id');
            }
        }
        return !empty($rankingIds) ? $rankingIds : [];
    }

    /**
     * 获取前台分类下对应的后端分类id
     * 包含前端子类目下对应的后端分类id
     */
    public static function getShopClassifyCateIds()
    {
        $infos = mShopCategoryClassify::selectInfos(['status' => mShopCategoryClassify::STATUS_NORMAL]);
        $firstInfos = [];
        $secondInfos = [];
        $thirdInfos = [];
        $fourInfos = [];
        foreach ($infos as $row) {
            switch ($row['deep']) {
                case mShopCategoryClassify::DEEP_FIRST_CLASSIFY:
                    $firstInfos[$row['id']] = $row;
                    break;
                case mShopCategoryClassify::DEEP_SECOND_CLASSIFY:
                    $secondInfos[$row['id']] = $row;
                    break;
                case mShopCategoryClassify::DEEP_THIRD_CLAORCATE:
                    $thirdInfos[$row['id']] = $row;
                    break;
                case  mShopCategoryClassify::DEEP_FOUR_CATEGORY;
                    $fourInfos[$row['id']] = $row;
                    break;
            }
        }

        $classifyCateIds = [];
        foreach ($thirdInfos as $row) {
            if ($row['cate_id'] > 0) {
                $secondId = $row['parent_id'];
                $secondInfo = $secondInfos[$secondId] ?? [];
                if ($secondInfo) {
                    $classifyCateIds[$secondId][] = $row['cate_id'];
                    $firstId = $secondInfo['parent_id'];
                    $firstInfo = $firstInfos[$firstId] ?? [];
                    if ($firstInfo) {
                        $classifyCateIds[$firstId][] = $row['cate_id'];
                    }
                }
            }
        }
        foreach ($fourInfos as $row) {
            if ($row['cate_id'] > 0) {
                $thirdId = $row['parent_id'];
                $thirdInfo = $thirdInfos[$thirdId] ?? [];
                if ($thirdInfo) {
                    $classifyCateIds[$thirdId][] = $row['cate_id'];
                    $secondId = $thirdInfo['parent_id'];
                    $secondInfo = $secondInfos[$secondId] ?? [];
                    if ($secondInfo) {
                        $classifyCateIds[$secondId][] = $row['cate_id'];
                        $firstId = $secondInfo['parent_id'];
                        $firstInfo = $firstInfos[$firstId] ?? [];
                        if ($firstInfo) {
                            $classifyCateIds[$firstId][] = $row['cate_id'];
                        }
                    }
                }
            }
        }
        $result = [];
        foreach ($classifyCateIds as $id => $cateIds) {
            $result[$id] = array_unique($cateIds);
        }
        return $result;
    }
}